home *** CD-ROM | disk | FTP | other *** search
/ Aminet 16 / Aminet 16 (1996)(GTI - Schatztruhe)[!][Dec 1996].iso / Aminet / comm / term / term_source.lha / Extras / Source / term-source.lha / Locale.c < prev    next >
C/C++ Source or Header  |  1996-10-20  |  18KB  |  832 lines

  1. /*
  2. **    Locale.c
  3. **
  4. **    Localization support routines
  5. **
  6. **    Copyright © 1990-1996 by Olaf `Olsen' Barthel
  7. **        All Rights Reserved
  8. **
  9. **    :ts=4
  10. */
  11.  
  12. #ifndef _GLOBAL_H
  13. #include "Global.h"
  14. #endif
  15.  
  16.     /* LocaleOpen(STRPTR CatalogName,STRPTR BuiltIn):
  17.      *
  18.      *    Open string translation tables.
  19.      */
  20.  
  21. VOID
  22. LocaleOpen(STRPTR CatalogName,STRPTR BuiltIn,LONG Version)
  23. {
  24.     DecimalPoint = ".";
  25.  
  26.     strcpy(ConvNumber,"%ld");
  27.     strcpy(ConvNumber10,"%10ld");
  28.  
  29.     if(LocaleBase = (struct LocaleBase *)OpenLibrary("locale.library",38))
  30.     {
  31.         if(LocaleBase->lb_SysPatches)
  32.         {
  33.             strcpy(ConvNumber,"%lD");
  34.             strcpy(ConvNumber10,"%10lD");
  35.  
  36.             if(Catalog = OpenCatalog(NULL,CatalogName,
  37.                 OC_BuiltInLanguage,    BuiltIn,
  38.                 OC_BuiltInCodeSet,    0,
  39.  
  40.                 Language[0] ? OC_Language : TAG_IGNORE,Language,
  41.             TAG_DONE))
  42.             {
  43.                 BOOL TooOld = FALSE;
  44.  
  45.                     /* Don't load an outdated catalog file */
  46.  
  47.                 if(Catalog->cat_Version < Version)
  48.                     TooOld = TRUE;
  49.                 else
  50.                 {
  51.                     if(strcmp(GetCatalogStr(Catalog,MSG_OFFSET_TEST1_TXT,""),"v4.0"))
  52.                         TooOld = TRUE;
  53.                 }
  54.  
  55.                 if(TooOld)
  56.                 {
  57.                     BOOL IntuitionOpen;
  58.  
  59.                     if(IntuitionBase)
  60.                         IntuitionOpen = TRUE;
  61.                     else
  62.                     {
  63.                         IntuitionOpen = FALSE;
  64.  
  65.                         IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",37);
  66.                     }
  67.  
  68.                     if(IntuitionBase)
  69.                         ShowRequest(NULL,"The catalog file is too old to be used\nwith this `term' revision.","Continue");
  70.  
  71.                     if(!IntuitionOpen)
  72.                     {
  73.                         CloseLibrary((struct Library *)IntuitionBase);
  74.                         IntuitionBase = NULL;
  75.                     }
  76.  
  77.                     CloseCatalog(Catalog);
  78.                     Catalog = NULL;
  79.                 }
  80.             }
  81.  
  82.             Locale = OpenLocale(NULL);
  83.  
  84.             DecimalPoint = Locale->loc_DecimalPoint;
  85.         }
  86.         else
  87.         {
  88.             CloseLibrary((struct Library *)LocaleBase);
  89.             LocaleBase = NULL;
  90.         }
  91.     }
  92.  
  93.         /* If we couldn't open locale.library or if the patches are
  94.          * not installed, and if we are running under Kickstart 2.04
  95.          * we'll change the number formatting codes in the built-in
  96.          * catalog strings.
  97.          */
  98.  
  99.     if(!LocaleBase && SysBase->LibNode.lib_Version == 37)
  100.     {
  101.         struct CatCompArrayType *Entry;
  102.         STRPTR String;
  103.         UBYTE c;
  104.         LONG i;
  105.  
  106.         for(i = 0, Entry = AppStrings ; i < NumAppStrings ; i++, Entry++)
  107.         {
  108.             String = Entry->cca_Str;
  109.  
  110.             while(c = *String++)
  111.             {
  112.                 if(c == '%' && *String != '%')
  113.                 {
  114.                     STATIC BYTE Stops[256] =
  115.                     {
  116.                         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  117.                         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  118.                         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  119.                         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  120.                         0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,
  121.                         0,0,0,1,0,1,0,0,1,0,0,0,0,0,0,0,
  122.                         0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,
  123.                         0,0,0,1,0,1,0,0,1,0,0,0,0,0,0,0,
  124.                         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  125.                         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  126.                         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  127.                         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  128.                         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  129.                         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  130.                         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  131.                         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  132.                     };
  133.  
  134.                     while(c = *String)
  135.                     {
  136.                         if(!Stops[c])
  137.                             String++;
  138.                         else
  139.                         {
  140.                             if(c == 'D')
  141.                                 *String = 'd';
  142.  
  143.                             break;
  144.                         }
  145.                     }
  146.  
  147.                     if(!c)
  148.                         break;
  149.                 }
  150.             }
  151.         }
  152.     }
  153. }
  154.  
  155.     /* LocaleClose():
  156.      *
  157.      *    Close the translation tables.
  158.      */
  159.  
  160. VOID
  161. LocaleClose()
  162. {
  163.     if(LocaleBase)
  164.     {
  165.         CloseLocale(Locale);
  166.         Locale = NULL;
  167.  
  168.         CloseCatalog(Catalog);
  169.         Catalog = NULL;
  170.  
  171.         CloseLibrary((struct Library *)LocaleBase);
  172.         LocaleBase = NULL;
  173.     }
  174. }
  175.  
  176.     /* LanguageCheck():
  177.      *
  178.      *    Checks to see if the currently selected language
  179.      *    is english.
  180.      */
  181.  
  182. VOID
  183. LanguageCheck()
  184. {
  185.     if(Locale && Catalog)
  186.     {
  187.         if(Locale->loc_LanguageName)
  188.         {
  189.             if(!Stricmp(Locale->loc_LanguageName,"english.language"))
  190.                 English = TRUE;
  191.             else
  192.                 English = FALSE;
  193.         }
  194.         else
  195.             English = FALSE;
  196.     }
  197.     else
  198.         English = TRUE;
  199. }
  200.  
  201.     /* SmallCurrency():
  202.      *
  203.      *    Support function for the rates control panel, returns a formatted
  204.      *    string to contain a string like "cents/unit".
  205.      */
  206.  
  207. VOID
  208. SmallCurrency(STRPTR Buffer,LONG BufferSize)
  209. {
  210.     if(Locale)
  211.         LimitedSPrintf(BufferSize,Buffer,LocaleString(MSG_RATEPANEL_PAY_PER_UNIT_GAD),Locale->loc_MonSmallCS);
  212.     else
  213.         LimitedSPrintf(BufferSize,Buffer,LocaleString(MSG_RATEPANEL_PAY_PER_UNIT_GAD),"Pay");
  214. }
  215.  
  216.     /* InsertGrouping(STRPTR Buffer,STRPTR GroupData,STRPTR GroupSeparator):
  217.      *
  218.      *    Tricky stuff, folks! This beauty will insert grouping characters
  219.      *    into a readily-prepared string buffer filled with numeric
  220.      *    contents. It takes the group separator tokens and group separator
  221.      *    strings into account.
  222.      */
  223.  
  224. VOID
  225. InsertGrouping(STRPTR Buffer,STRPTR GroupData,STRPTR GroupSeparator)
  226. {
  227.     UBYTE    LocalBuffer[80];    /* Sufficient, but too large */
  228.     STRPTR    Index;
  229.     LONG    i,j,SeparatorSize;
  230.     LONG    Count;                /* How many characters per group */
  231.     BOOL    RepeatGroupCount;    /* Keep repeating group size until end */
  232.  
  233.     RepeatGroupCount = FALSE;
  234.  
  235.         /* Set up for the first group */
  236.  
  237.     switch(*GroupData)
  238.     {
  239.         case 0:            /* Repeat current grouping scheme until end */
  240.         case 255:        /* No further grouping is to be performed */
  241.  
  242.             Count = 0;
  243.  
  244.             break;
  245.  
  246.         default:        /* Initial group size */
  247.  
  248.             Count = *GroupData++;
  249.  
  250.             break;
  251.     }
  252.  
  253.         /* Check the size of the group separator string */
  254.  
  255.     if((SeparatorSize = strlen(GroupSeparator) - 1) < 1)
  256.         Count = 0;
  257.  
  258.         /* That where we'll start */
  259.  
  260.     Index = LocalBuffer;
  261.  
  262.         /* Build the string back to front, we will reverse it later */
  263.  
  264.     for(i = strlen(Buffer) - 1, j = 1 ; i >= 0 ; i--, j++)
  265.     {
  266.             /* Pick up the next number character */
  267.  
  268.         *Index++ = Buffer[i];
  269.  
  270.             /* Are we to insert the grouping characters here? */
  271.  
  272.         if(Count && j == Count)
  273.         {
  274.             LONG k;
  275.  
  276.                 /* Insert the grouping characters */
  277.  
  278.             for(k = SeparatorSize ; k >= 0 ; k--)
  279.                 *Index++ = GroupSeparator[k];
  280.  
  281.                 /* Reset the group size counter */
  282.  
  283.             j = 0;
  284.  
  285.                 /* Pick up the next grouping token? */
  286.  
  287.             if(!RepeatGroupCount)
  288.             {
  289.                     /* Ok, what kind of token is it? */
  290.  
  291.                 switch(*GroupData)
  292.                 {
  293.                     case 0:        /* Repeat current grouping scheme */
  294.  
  295.                         RepeatGroupCount = TRUE;
  296.                         break;
  297.  
  298.                     case 255:    /* Perform no further grouping */
  299.  
  300.                         Count = 0;
  301.                         break;
  302.  
  303.                     default:    /* New group size */
  304.  
  305.                         Count = *GroupData++;
  306.                         break;
  307.                 }
  308.             }
  309.         }
  310.     }
  311.  
  312.         /* Look how long the resulting string is */
  313.  
  314.     j = ((LONG)Index - (LONG)LocalBuffer) - 1;
  315.  
  316.         /* Copy it back */
  317.  
  318.     Index = Buffer;
  319.  
  320.         /* Reverse the order of characters while copying */
  321.  
  322.     for(i = j ; i >= 0 ; i--)
  323.         *Index++ = LocalBuffer[i];
  324.  
  325.         /* Provide null-termination */
  326.  
  327.     *Index = 0;
  328. }
  329.  
  330. STATIC VOID
  331. ConvertMonetaryQuantity(LONG Units,STRPTR Destination,LONG DestinationSize,BOOL UseCurrency)
  332. {
  333.     UBYTE    IntegerBuffer[80];    /* Sufficient, but too large */
  334.  
  335.     STRPTR    SignText,            /* Signed/unsigned quantity text */
  336.             SpaceText,            /* Currency/number separation */
  337.             Currency;            /* The name of the currency */
  338.     LONG    SpaceSep,            /* A space separates currency and quantity? */
  339.             SignPos,            /* Where to place the sign text */
  340.             CSPos;                /* Where to place the currency text */
  341.     LONG    Sign;                /* Negative or positive quantity? */
  342.  
  343.         /* Negative quantity? */
  344.  
  345.     if(Units < 0)
  346.     {
  347.         Sign = -1;
  348.  
  349.         Units = -Units;
  350.     }
  351.     else
  352.         Sign = 1;
  353.  
  354.         /* Does this currency sport a fractional smaller currency? */
  355.  
  356.     if(Locale->loc_MonFracDigits)
  357.     {
  358.         UBYTE    NumberBuffer[10],
  359.                 FractionBuffer[40];
  360.         LONG    Integer,
  361.                 Fraction,
  362.                 Scale;
  363.         LONG    i;
  364.  
  365.             /* Prepare the formatting string */
  366.  
  367.         LimitedSPrintf(sizeof(NumberBuffer),NumberBuffer,"%%0%ldld",Locale->loc_MonFracDigits);
  368.  
  369.             /* Turn the number of fractional digits into a power of ten */
  370.  
  371.         for(i = 0, Scale = 1 ; i < Locale->loc_MonFracDigits ; i++)
  372.             Scale *= 10;
  373.  
  374.             /* Split the quantity in integer and fractional part */
  375.  
  376.         Integer        = Units / Scale;
  377.         Fraction    = Units % Scale;
  378.  
  379.             /* Build the integer text */
  380.  
  381.         LimitedSPrintf(sizeof(IntegerBuffer),IntegerBuffer,"%ld",Integer);
  382.  
  383.         InsertGrouping(IntegerBuffer,Locale->loc_MonGrouping,Locale->loc_MonGroupSeparator);
  384.  
  385.             /* Build the fractional text */
  386.  
  387.         LimitedSPrintf(sizeof(FractionBuffer),FractionBuffer,NumberBuffer,Fraction);
  388.  
  389.         InsertGrouping(FractionBuffer,Locale->loc_MonFracGrouping,Locale->loc_MonFracGroupSeparator);
  390.  
  391.             /* Add the monetary decimal point */
  392.  
  393.         LimitedStrcat(sizeof(IntegerBuffer),IntegerBuffer,Locale->loc_MonDecimalPoint);
  394.  
  395.             /* Add the fractional part */
  396.  
  397.         LimitedStrcat(sizeof(IntegerBuffer),IntegerBuffer,FractionBuffer);
  398.     }
  399.     else
  400.     {
  401.             /* Build the integer text */
  402.  
  403.         LimitedSPrintf(sizeof(IntegerBuffer),IntegerBuffer,"%ld",Units);
  404.  
  405.         InsertGrouping(IntegerBuffer,Locale->loc_MonGrouping,Locale->loc_MonGroupSeparator);
  406.     }
  407.  
  408.         /* Pick up the appropriate formatting parameters */
  409.  
  410.     if(Sign < 0)
  411.     {
  412.         SignText    = Locale->loc_MonNegativeSign;
  413.         SpaceSep    = Locale->loc_MonNegativeSpaceSep;
  414.         SignPos        = Locale->loc_MonNegativeSignPos;
  415.         CSPos        = Locale->loc_MonNegativeCSPos;
  416.     }
  417.     else
  418.     {
  419.         SignText    = Locale->loc_MonPositiveSign;
  420.         SpaceSep    = Locale->loc_MonPositiveSpaceSep;
  421.         SignPos        = Locale->loc_MonPositiveSignPos;
  422.         CSPos        = Locale->loc_MonPositiveCSPos;
  423.     }
  424.  
  425.         /* Are we to use the currency symbol? */
  426.  
  427.     if(UseCurrency)
  428.     {
  429.             /* Pick up the currency text */
  430.  
  431.         Currency = Locale->loc_MonCS;
  432.  
  433.             /* Take care of the separation information */
  434.  
  435.         if(SpaceSep == SS_NOSPACE)
  436.             SpaceText = "";
  437.         else
  438.             SpaceText = " ";
  439.     }
  440.     else
  441.         Currency = SpaceText = "";
  442.  
  443.         /* Now merge all the information into one single string */
  444.  
  445.     if(CSPos == CSP_PRECEDES)
  446.     {
  447.         switch(SignPos)
  448.         {
  449.             case SP_PARENS:
  450.  
  451.                 /* (Currency <Space> Sign Value) */
  452.                 LimitedSPrintf(DestinationSize,Destination,"(%s%s%s%s)",Currency,SpaceText,SignText,IntegerBuffer);
  453.                 break;
  454.  
  455.             case SP_PREC_ALL:
  456.  
  457.                 /* Sign Currency <Space> Value */
  458.                 LimitedSPrintf(DestinationSize,Destination,"%s%s%s%s",SignText,Currency,SpaceText,IntegerBuffer);
  459.                 break;
  460.  
  461.             case SP_SUCC_ALL:
  462.  
  463.                 /* Currency <Space> Value Sign */
  464.                 LimitedSPrintf(DestinationSize,Destination,"%s%s%s%s",Currency,SpaceText,IntegerBuffer,SignText);
  465.                 break;
  466.  
  467.             case SP_PREC_CURR:
  468.  
  469.                 /* Sign Currency <Space> Value */
  470.                 LimitedSPrintf(DestinationSize,Destination,"%s%s%s%s",SignText,Currency,SpaceText,IntegerBuffer);
  471.                 break;
  472.  
  473.             case SP_SUCC_CURR:
  474.  
  475.                 /* Currency Sign <Space> Value */
  476.                 LimitedSPrintf(DestinationSize,Destination,"%s%s%s%s",Currency,SignText,SpaceText,IntegerBuffer);
  477.                 break;
  478.         }
  479.     }
  480.     else
  481.     {
  482.         switch(SignPos)
  483.         {
  484.             case SP_PARENS:
  485.  
  486.                 /* (Sign Value <Space> Currency) */
  487.                 LimitedSPrintf(DestinationSize,Destination,"(%s%s%s%s)",SignText,IntegerBuffer,SpaceText,Currency);
  488.                 break;
  489.  
  490.             case SP_PREC_ALL:
  491.  
  492.                 /* Sign Value <Space> Currency */
  493.                 LimitedSPrintf(DestinationSize,Destination,"%s%s%s%s",SignText,IntegerBuffer,SpaceText,Currency);
  494.                 break;
  495.  
  496.             case SP_SUCC_ALL:
  497.  
  498.                 /* Value <Space> Currency Sign */
  499.                 LimitedSPrintf(DestinationSize,Destination,"%s%s%s%s",IntegerBuffer,SpaceText,Currency,SignText);
  500.                 break;
  501.  
  502.             case SP_PREC_CURR:
  503.  
  504.                 /* Value <Space> Sign Currency */
  505.                 LimitedSPrintf(DestinationSize,Destination,"%s%s%s%s",IntegerBuffer,SpaceText,SignText,Currency);
  506.                 break;
  507.  
  508.             case SP_SUCC_CURR:
  509.  
  510.                 /* Value <Space> Currency Sign */
  511.                 LimitedSPrintf(DestinationSize,Destination,"%s%s%s%s",IntegerBuffer,SpaceText,Currency,SignText);
  512.                 break;
  513.         }
  514.     }
  515. }
  516.  
  517.     /* CreateSum(LONG Quantity):
  518.      *
  519.      *    Create a string containing a monetary quantity formatted
  520.      *    according to the current locale rules.
  521.      */
  522.  
  523. VOID
  524. CreateSum(LONG Quantity,BOOL UseCurrency,STRPTR Buffer,LONG BufferSize)
  525. {
  526.     if(Locale)
  527.         ConvertMonetaryQuantity(Quantity,Buffer,BufferSize,UseCurrency);
  528.     else
  529.         LimitedSPrintf(BufferSize,Buffer,"%ld.%02ld",Quantity / 100,Quantity % 100);
  530. }
  531.  
  532.     /* LocalizeString(STRPTR *Strings,LONG From,LONG To):
  533.      *
  534.      *    Localize an array of strings.
  535.      */
  536.  
  537. VOID
  538. LocalizeString(STRPTR *Strings,LONG From,LONG To)
  539. {
  540.     if(!Strings[0])
  541.     {
  542.         LONG i,j;
  543.  
  544.         for(i = From, j = 0 ; i <= To ; i++, j++)
  545.             Strings[j] = LocaleString(i);
  546.     }
  547. }
  548.  
  549.     /* LocalizeStringTable(STRPTR *Strings,LONG *Table)
  550.      *
  551.      *    Localize an array of strings by table.
  552.      */
  553.  
  554. VOID
  555. LocalizeStringTable(STRPTR *Strings,LONG *Table)
  556. {
  557.     while(*Table != -1)
  558.         *Strings++ = LocaleString(*Table++);
  559.  
  560.     *Strings = NULL;
  561. }
  562.  
  563.     /* LocaleString(ULONG ID):
  564.      *
  565.      *    Obtain a string from the translation pool.
  566.      */
  567.  
  568. STRPTR
  569. LocaleString(ULONG ID)
  570. {
  571.     STRPTR Builtin;
  572.  
  573.     if(ID < NumAppStrings && AppStrings[ID].cca_ID == ID)
  574.         Builtin = AppStrings[ID].cca_Str;
  575.     else
  576.     {
  577.         LONG Left,Mid,Right;
  578.  
  579.             /* Binary search, note: can be applied here */
  580.             /* only because the catalog entries are */
  581.             /* stored in ascending ID order. But actually, */
  582.             /* this piece of code should never get called. */
  583.  
  584.         Left    = 0;
  585.         Right    = NumAppStrings - 1;
  586.  
  587.         do
  588.         {
  589.             Mid = (Left + Right) / 2;
  590.  
  591.             if(ID < AppStrings[Mid].cca_ID)
  592.                 Right    = Mid - 1;
  593.             else
  594.                 Left    = Mid + 1;
  595.         }
  596.         while(ID != AppStrings[Mid].cca_ID && Left <= Right);
  597.  
  598.         if(ID == AppStrings[Mid].cca_ID)
  599.             Builtin = AppStrings[Mid].cca_Str;
  600.         else
  601.             Builtin = "";
  602.     }
  603.  
  604.     if(Catalog)
  605.     {
  606.         STRPTR String = GetCatalogStr(Catalog,ID,Builtin);
  607.  
  608.         if(String[0])
  609.             return(String);
  610.     }
  611.  
  612.     return(Builtin);
  613. }
  614.  
  615. STRPTR SAVE_DS ASM
  616. LocaleHookFunc(REG(a0) struct Hook *UnusedHook,REG(a2) APTR Unused,REG(a1) LONG ID)
  617. {
  618.     return(LocaleString(ID));
  619. }
  620.  
  621. STATIC LONG SAVE_DS ASM
  622. FormatDateHookFunc(REG(a0) struct Hook *Hook,REG(a2) APTR Unused,REG(a1) UBYTE Char)
  623. {
  624.     struct FormatContext *Context = Hook->h_Data;
  625.  
  626.     if(Context->Size > 0)
  627.     {
  628.         *Context->Index++ = Char;
  629.  
  630.         if(--Context->Size == 1)
  631.         {
  632.             *Context->Index = 0;
  633.             Context->Size = 0;
  634.         }
  635.     }
  636.  
  637.     return(TRUE);
  638. }
  639.  
  640.     /* FormatStamp():
  641.      *
  642.      *    Convert a date stamp into human readable
  643.      *    form by taking the current locale parameters
  644.      *    into account.
  645.      */
  646.  
  647. BOOL
  648. FormatStamp(struct DateStamp *Stamp,STRPTR BothBuffer,LONG BothBufferSize,BOOL SubstituteDay)
  649. {
  650.     struct DateStamp Now;
  651.  
  652.         /* If no time stamp given, do with current time */
  653.  
  654.     if(!Stamp)
  655.         CurrentTimeToStamp(Stamp = &Now);
  656.  
  657.         /* Is the current locale available? */
  658.  
  659.     if(Locale)
  660.     {
  661.         struct FormatContext Context;
  662.         struct Hook LocalHook;
  663.  
  664.         InitHook(&LocalHook,(HOOKFUNC)FormatDateHookFunc,&Context);
  665.  
  666.             /* Combine date and time text? */
  667.  
  668.         if(!SubstituteDay)
  669.         {
  670.             Context.Index    = BothBuffer;
  671.             Context.Size    = BothBufferSize;
  672.  
  673.             FormatDate(Locale,Locale->loc_DateTimeFormat,Stamp,&LocalHook);
  674.  
  675.             StripSpaces(BothBuffer);
  676.         }
  677.         else
  678.         {
  679.             UBYTE DateBuffer[40],TimeBuffer[40];
  680.  
  681.                 /* Are we to substitute the current day with */
  682.                 /* text such as today, yesterday, etc.? */
  683.  
  684.             if(SubstituteDay)
  685.             {
  686.                 struct DateStamp Today;
  687.                 STRPTR String;
  688.  
  689.                     /* Get the current time */
  690.  
  691.                 CurrentTimeToStamp(&Today);
  692.  
  693.                     /* Does the date refer to yesterday? */
  694.  
  695.                 if(Stamp->ds_Days == Today.ds_Days - 1)
  696.                     String = GetLocaleStr(Locale,YESTERDAYSTR);
  697.                 else
  698.                 {
  699.                         /* Does the date refer to today? */
  700.  
  701.                     if(Stamp->ds_Days == Today.ds_Days)
  702.                         String = GetLocaleStr(Locale,TODAYSTR);
  703.                     else
  704.                     {
  705.                             /* Does the date refer to tomorrow? */
  706.  
  707.                         if(Stamp->ds_Days == Today.ds_Days + 1)
  708.                             String = GetLocaleStr(Locale,TOMORROWSTR);
  709.                         else
  710.                         {
  711.                             String            = NULL;
  712.                             SubstituteDay    = FALSE;
  713.                         }
  714.                     }
  715.                 }
  716.  
  717.                 if(String)
  718.                     LimitedStrcpy(sizeof(DateBuffer),DateBuffer,String);
  719.                 else
  720.                     DateBuffer[0] = 0;
  721.             }
  722.  
  723.             if(!SubstituteDay)
  724.             {
  725.                 Context.Index    = DateBuffer;
  726.                 Context.Size    = sizeof(DateBuffer);
  727.  
  728.                 FormatDate(Locale,Locale->loc_DateFormat,Stamp,&LocalHook);
  729.             }
  730.  
  731.             StripSpaces(DateBuffer);
  732.  
  733.             Context.Index    = TimeBuffer;
  734.             Context.Size    = sizeof(TimeBuffer);
  735.  
  736.             FormatDate(Locale,Locale->loc_TimeFormat,Stamp,&LocalHook);
  737.  
  738.             StripSpaces(TimeBuffer);
  739.  
  740.                 /* Combine date and time */
  741.  
  742.             LimitedSPrintf(BothBufferSize,BothBuffer,"%s %s",DateBuffer,TimeBuffer);
  743.         }
  744.     }
  745.     else
  746.     {
  747.         UBYTE DateBuffer[40],TimeBuffer[40];
  748.         struct DateTime    DateTime;
  749.  
  750.             /* No locale, so we will use dos.library instead. */
  751.  
  752.         CopyMem(Stamp,&DateTime.dat_Stamp,sizeof(struct DateStamp));
  753.  
  754.         DateTime.dat_Format        = FORMAT_DOS;
  755.         DateTime.dat_Flags        = SubstituteDay ? DTF_SUBST : NULL;
  756.         DateTime.dat_StrDay        = NULL;
  757.         DateTime.dat_StrDate    = DateBuffer;
  758.         DateTime.dat_StrTime    = TimeBuffer;
  759.  
  760.         if(!DateToStr(&DateTime))
  761.             return(FALSE);
  762.  
  763.         StripSpaces(DateBuffer);
  764.         StripSpaces(TimeBuffer);
  765.  
  766.             /* Combine date and time */
  767.  
  768.         LimitedSPrintf(BothBufferSize,BothBuffer,"%s %s",DateBuffer,TimeBuffer);
  769.     }
  770.  
  771.     return(TRUE);
  772. }
  773.  
  774.     /* FormatTime(STRPTR Buffer,LONG Hours,LONG Minutes,LONG Seconds):
  775.      *
  776.      *    Given hours, minutes and seconds, format this data into
  777.      *    a human-readable string.
  778.      */
  779.  
  780. VOID
  781. FormatTime(STRPTR Buffer,LONG BufferSize,LONG Hours,LONG Minutes,LONG Seconds)
  782. {
  783.     if(Locale)
  784.     {
  785.         struct Hook                LocalHook;
  786.         struct FormatContext    Context;
  787.         struct DateStamp        Stamp;
  788.  
  789.         Stamp.ds_Days        = 0;
  790.         Stamp.ds_Minute        = Hours * 60 + Minutes;
  791.         Stamp.ds_Tick        = MAX(0,Seconds) * TICKS_PER_SECOND;
  792.  
  793.         Context.Index    = Buffer;
  794.         Context.Size    = BufferSize;
  795.  
  796.         InitHook(&LocalHook,(HOOKFUNC)FormatDateHookFunc,&Context);
  797.  
  798.         if(Seconds < 0)
  799.             FormatDate(Locale,Locale->loc_ShortTimeFormat,&Stamp,&LocalHook);
  800.         else
  801.             FormatDate(Locale,Locale->loc_TimeFormat,&Stamp,&LocalHook);
  802.     }
  803.     else
  804.     {
  805.         if(Seconds < 0)
  806.             LimitedSPrintf(BufferSize,Buffer,"%02ld:%02ld",Hours,Minutes);
  807.         else
  808.             LimitedSPrintf(BufferSize,Buffer,"%02ld:%02ld:%02ld",Hours,Minutes,Seconds);
  809.     }
  810. }
  811.  
  812.     /* StandardShowTime(struct Gadget *SomeGadget,LONG Level):
  813.      *
  814.      *    Callback routine to display some time level.
  815.      */
  816.  
  817. STRPTR SAVE_DS STACKARGS
  818. StandardShowTime(struct Gadget *UnusedGadget,LONG Seconds)
  819. {
  820.     STATIC UBYTE Time[10];
  821.     STRPTR FormatString;
  822.  
  823.     if(LocaleBase)
  824.         FormatString = "%2lD%s%02lD";
  825.     else
  826.         FormatString = "%2ld%s%02ld";
  827.  
  828.     LimitedSPrintf(sizeof(Time),Time,FormatString,Seconds / 100,DecimalPoint,Seconds % 100);
  829.  
  830.     return(Time);
  831. }
  832.